這裡會介紹 Thread, Runnable, Handler, AsyncTask等相關的android thread class。
android 程式一開啟的時候,系統會創造並執行一個main thread。所有UI顯示或者widget的event都在這個thread完成,所以又名 UI thread。有時候我們需要進行一些比較花時間的運算,為了避免UI thread的阻塞,我們必須另外使用另外一個thread來處理(worker thread)。而使用thread的方法很簡單,只需要定義run()方法再叫用run()函式即可。
為了閱讀性及彈性,Android API有另外提供一個 Runnable 的介面。Runnable 裡面定義了 run() function,我們僅需要把Runnable 物件丟給thread執行就可以了。就像是把工作(Runnable)交給工人(worker thread)一樣。
|
|
如果task不需要重複利用,也可以不要存成變數而直接在new thread時再宣告(如下)。其實跟第一個方法很像,只是我們run定義在runable interface。
Thread使用上滿簡單的,不過還是有一些要注意的地方。Android API Guide 提到Thread有兩個原則要遵守:
- Do not block the UI thread
- Do not access the Android UI toolkit from outside the UI thread
所以在worker thread 千萬不能直接使用UI的元件,否則會造成run-time exception error 或者其他未知的問題。雖然不能直接存取UI,但是可以使用間接的方式來存取。thread之間彼此溝通方式有很多,其中一種就是message。Android提供一個 Handler類別來充當thread間的溝通介面,在這裡舉的例子是 worker thread 與 UI thread(activity) 之間的溝通。
Handler 的 功用主要有兩個:
- to enqueue an action to be performed on a different thread than your own.
- to schedule messages and runnables to be executed as some point in the future
第一個功能是藉由 message queue 來處理其他 thread 的訊息
另外一個功能則是排程工作或訊息
除了post以及sendEmptyMessage之外,Handler另外也提供了一些函式可以用在訊息排程:
- postAtTime(Runnable, long)
- postDelayed(Runnable, long)
- sendMessage(Message)
- sendMessageAtTime(Message, long)
- sendMessageDelayed(Message, long)
如果你是要直接使用UI Thread的元件,也可以直接透過下列的method操作:
臨時性的操作不同thread可以利用上面的作法,不過大量使用程式碼會變得不容易閱讀。Android 這裡有提供一個 AsyncTask Class 來簡化thread與handler之間的操作。你可以在文件裡面可以找到更詳細介紹以及使用方法。使用AsyncTask可以讓程式碼變得很簡潔:
當然AsyncTask還是有一些限制的:
- The AsyncTask class must be loaded on the UI thread. This is done automatically as of JELLY_BEAN.
- The task instance must be created on the UI thread.
- execute(Params…) must be invoked on the UI thread.
- Do not call onPreExecute(), onPostExecute(Result), doInBackground(Params…), onProgressUpdate(Progress…) manually.
- The task can be executed only once (an exception will be thrown if a second execution is attempted.)
AsyncTask的設計適合用來作短時間且一次性的工作。如果想處理長時間的工作,文件建議我們使用 java.util.concurrent pacakge的類別,如Executor, ThreadPoolExecutor 或是 FutureTask。若想要處理重複有週期性的工作,則可以使用Timer與TimerTask。